#include "draw_utils.h"
#include "camera.h"
#include "application.h"

//-----------------------------------------------------------------------------
TCamera camera;
#include "entity3d.h"

TEntity3D e1;
TEntity3D e2;

struct TCameraController3rdPerson {
	TEntity3D *target;
	float      distance_to_target;
	float      yaw, pitch;

	TCameraController3rdPerson( ) 
	: distance_to_target( 10.0f )
	{ }

	void update( TCamera *camera ) {
		D3DXVECTOR3 src = target->getPosition() - distance_to_target * target->getFront();
		src.y = 10.0f;
		camera->lookAt( src, target->getPosition(), D3DXVECTOR3(0,1,0));
	}
};

TCameraController3rdPerson camera_controller;

//-----------------------------------------------------------------------------
void TApplication::onBoot() {
    // Turn off culling, so we see the front and back of the triangle
    g_pd3dDevice->SetRenderState( D3DRS_CULLMODE, D3DCULL_NONE );

    // Turn off D3D lighting, since we are providing our own vertex colors
    g_pd3dDevice->SetRenderState( D3DRS_AMBIENT, 0xffffffff );

	camera.lookAt( D3DXVECTOR3( 0,5,10 )
		         , D3DXVECTOR3( 0,0,0 )
		         , D3DXVECTOR3( 0,1,0 ));
	camera.setProjectionParams( D3DXToRadian( 65.0f ), static_cast<float>(xres) / static_cast<float>(yres), 1.0f, 100.0f );

	e1.setPosition( D3DXVECTOR3( 0,5,2 ) );
	e2.setPosition( D3DXVECTOR3( 3,0,0 ) );

	//D3DXMatrixRotationY( &e1.world, D3DXToRadian( 30.0f ) );

	camera_controller.target = &e1;
	e1.init_graphics(g_pd3dDevice);
}


//-----------------------------------------------------------------------------
VOID SetupCameraMatrices()
{
    // For our world matrix, we will just rotate the object about the y-
    D3DXMATRIXA16 matWorld;
	D3DXMatrixIdentity( &matWorld );
	g_pd3dDevice->SetTransform( D3DTS_WORLD, &matWorld );
    g_pd3dDevice->SetTransform( D3DTS_VIEW, &camera.getView() );
    g_pd3dDevice->SetTransform( D3DTS_PROJECTION, &camera.getProjection() );
}

//-----------------------------------------------------------------------------
void TApplication::update( float delta ) {
	(void) delta;

	// Mover la entidad
	float amount_moved = delta * 40.0f;
	float amount_rotated = delta * 3.0f;
	if( isPressed( 'W' ) )
		e1.move( e1.getFront() * amount_moved );
	if( isPressed( 'S' ) )
		e1.move( -e1.getFront() * amount_moved );
	if( isPressed( 'A' ) )
		e1.move( e1.getLeft() * amount_moved );
	if( isPressed( 'D' ) )
		e1.move( -e1.getLeft() * amount_moved );
	if( isPressed( 'Q' ) ) {
		e1.move( e1.getLeft() * amount_moved*4 ),
		e1.rotateY( -amount_rotated );
	}
		
	if( isPressed( 'E' ) ) {
		e1.move( -e1.getLeft() * amount_moved*4 ),
		e1.rotateY( amount_rotated );
	}
		
	
	if( isPressed( 'T' ) ) {
		//
		D3DXVECTOR3 delta = e2.getPosition( ) - e1.getPosition();
		
		// Normalizar para el dot product me de el cos_angle
		// sin el modulo de e1, e2
		D3DXVec3Normalize( &delta, &delta );
		
		// Calcular diferencia de angulos
		// entre el delta y el right 
		// El right y no el front para poder usar el
		// > 0 or < 0 para el signo del giro
		D3DXVECTOR3 right = -e1.getLeft();
		float cos_angle = D3DXVec3Dot( &delta
			                         , &right );
		
		// Cual es el error en radianes en valor absoluto?
		float angle = fabsf( acos( cos_angle ) - D3DX_PI * 0.5f );

		// No gires mas del error!. amount_rotated > 0!!
		if( amount_rotated > angle )
			amount_rotated = angle;

		// Cual es el signo del error
		if( cos_angle > 0 ) {
			e1.rotateY( -amount_rotated );
		} else if( cos_angle < 0 ) {
			e1.rotateY( amount_rotated );
		}

	}

	//camera_controller.update( &camera );
}

//-----------------------------------------------------------------------------
void TApplication::render()
{
    // Clear the backbuffer to a black color
    g_pd3dDevice->Clear( 0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER,
                         D3DCOLOR_XRGB( 0, 0, 255 ), 1.0f, 0 );

    // Begin the scene
    if( SUCCEEDED( g_pd3dDevice->BeginScene() ) )
    {
        // Setup the world, view, and projection matrices
        SetupCameraMatrices();
		drawGridXZ( 10, 5 );
		//drawAxis( );
		
		e1.render(g_pd3dDevice);


		static float time = 0.0f;
		time += 0.016f;
		e2.setPosition( D3DXVECTOR3( 10 + 5 * sin( time ), 0, 0 ) );
		//e2.render();

        // End the scene
        g_pd3dDevice->EndScene();
    }

    // Present the backbuffer contents to the display
    g_pd3dDevice->Present( NULL, NULL, NULL, NULL );
}






